home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * CBsp-Aux.c - Bspline curve auxilary routines. *
- *******************************************************************************
- * Written by Gershon Elber, Aug. 90. *
- ******************************************************************************/
-
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
- #include "cagd_loc.h"
-
- /******************************************************************************
- * Given a bspline curve - subdivide it into two at the given parametric value.*
- * Returns pointer to first curve in a list of two curves (subdivided ones). *
- * The subdivision is achieved by inserting (order-1) knot at the given param. *
- * value t and spliting the control polygon and knot vector at that point. *
- ******************************************************************************/
- CagdCrvStruct *BspCrvSubdivAtParam(CagdCrvStruct *Crv, CagdRType t)
- {
- CagdBType
- IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
- int i, j,
- k = Crv -> Order,
- Len = Crv -> Length,
- KVLen = k + Len,
- Index1 = BspKnotLastIndexL(Crv -> KnotVector, KVLen, t),
- Index2 = BspKnotFirstIndexG(Crv -> KnotVector, KVLen, t),
- Mult = k - 1 - (Index2 - Index1 - 1),
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
- CagdRType TMin, TMax, *LOnePts, *ROnePts, *OnePts, *NewKV,
- **Pts, **LPts, **RPts;
- CagdCrvStruct *LCrv, *RCrv;
- BspKnotAlphaCoeffType *A;
-
- CagdCrvDomain(Crv, &TMin, &TMax);
- if (t < TMin || APX_EQ(t, TMin) ||
- t > TMax || APX_EQ(t, TMax))
- FATAL_ERROR(CAGD_ERR_T_NOT_IN_CRV);
-
- LCrv = BspCrvNew(Index1 + 1, k, Crv -> PType);
- RCrv = BspCrvNew(Len - Index2 + k, k, Crv -> PType);
-
- /* Update the new knot vectors. */
- CAGD_GEN_COPY(LCrv -> KnotVector,
- Crv -> KnotVector,
- sizeof(CagdRType) * (Index1 + 1));
- /* Close the knot vector with multiplicity Order: */
- for (j = Index1 + 1; j <= Index1 + k; j++)
- LCrv -> KnotVector[j] = t;
- CAGD_GEN_COPY(&RCrv -> KnotVector[k],
- &Crv -> KnotVector[Index2],
- sizeof(CagdRType) * (Len + k - Index2));
- /* Make sure knot vector starts with multiplicity Order: */
- for (j = 0; j < k; j++)
- RCrv -> KnotVector[j] = t;
-
- /* Now handle the control polygon refinement. */
- Pts = Crv -> Points,
- LPts = LCrv -> Points,
- RPts = RCrv -> Points;
-
- if (Mult > 0) {
- NewKV = IritMalloc(sizeof(CagdRType) * Mult);
- for (i = 0; i < Mult; i++)
- NewKV[i] = t;
- A = BspKnotEvalAlphaCoefMerge(k, Crv -> KnotVector, Len, NewKV,
- Mult);
- IritFree((VoidPtr) NewKV);
- }
- else {
- A = BspKnotEvalAlphaCoef(k, Crv -> KnotVector, Len,
- Crv -> KnotVector, Len);
- }
-
- /* Note that Mult can be negative in cases where original */
- /* multiplicity was order or more and we need to compensate */
- /* here, since Alpha matrix will be just a unit matrix then. */
- Mult = Mult >= 0 ? 0 : -Mult;
-
- /* Blend Crv into LCrv. */
- for (j = IsNotRational; j <= MaxCoord; j++) {
- LOnePts = LPts[j];
- OnePts = Pts[j];
- for (i = 0; i < LCrv -> Length; i++, LOnePts++)
- CAGD_ALPHA_BLEND( A, i, OnePts, LOnePts );
- }
-
- /* Blend Crv into RCrv. */
- for (j = IsNotRational; j <= MaxCoord; j++) {
- ROnePts = RPts[j];
- OnePts = Pts[j];
- for (i = LCrv -> Length - 1 + Mult;
- i < LCrv -> Length + RCrv -> Length - 1 + Mult;
- i++, ROnePts++)
- CAGD_ALPHA_BLEND( A, i, OnePts, ROnePts );
- }
-
- BspKnotFreeAlphaCoef(A);
-
- BspKnotMakeRobustKV(RCrv -> KnotVector,
- RCrv -> Order + RCrv -> Length);
- BspKnotMakeRobustKV(LCrv -> KnotVector,
- LCrv -> Order + LCrv -> Length);
-
- LCrv -> Pnext = RCrv;
-
- return LCrv;
- }
-
- /******************************************************************************
- * Insert n knot all with the value t. In no case will the multiplicity of *
- * knot be greater or equal to the curve order. *
- ******************************************************************************/
- CagdCrvStruct *BspCrvKnotInsertNSame(CagdCrvStruct *Crv, CagdRType t, int n)
- {
- int i,
- CrntMult = BspKnotFindMult(Crv -> KnotVector, Crv -> Order,
- Crv -> Length, t),
- Mult = MIN(n, Crv -> Order - CrntMult - 1);
- CagdCrvStruct *RefinedCrv;
-
- if (Mult > 0) {
- CagdRType
- *NewKV = (CagdRType *) IritMalloc(sizeof(CagdRType) * Mult);
-
- for (i = 0; i < Mult; i++)
- NewKV[i] = t;
-
- RefinedCrv = BspCrvKnotInsertNDiff(Crv, FALSE, NewKV, Mult);
-
- IritFree((VoidPtr) NewKV);
- }
- else {
- RefinedCrv = CagdCrvCopy(Crv);
- }
-
- return RefinedCrv;
- }
-
- /******************************************************************************
- * Insert n knot with different values as defined by t. If however Replace is *
- * TRUE, the knot are simply replacing the current ones. *
- ******************************************************************************/
- CagdCrvStruct *BspCrvKnotInsertNDiff(CagdCrvStruct *Crv, CagdBType Replace,
- CagdRType *t, int n)
- {
- CagdBType
- IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
- CagdRType
- *KnotVector = Crv -> KnotVector;
- int Order = Crv -> Order,
- Length = Crv -> Length,
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
- CagdCrvStruct *RefinedCrv;
-
- if (Replace) {
- int i;
-
- if (Order + Length != n)
- FATAL_ERROR(CAGD_ERR_NUM_KNOT_MISMATCH);
- for (i = 1; i < n; i++)
- if (t[i] < t[i - 1])
- FATAL_ERROR(CAGD_ERR_KNOT_NOT_ORDERED);
-
- RefinedCrv = CagdCrvCopy(Crv);
- for (i = 0; i < n; i++)
- RefinedCrv -> KnotVector[i] = *t++;
- }
- else if (n == 0) {
- RefinedCrv = CagdCrvCopy(Crv);
- }
- else {
- int i, j, LengthKVt;
- BspKnotAlphaCoeffType *A;
- CagdRType *MergedKVt;
-
- /* Compute the Alpha refinement matrix. */
- MergedKVt = BspKnotMergeTwo(KnotVector, Length + Order,
- t, n, 0, &LengthKVt);
- A = BspKnotEvalAlphaCoef(Order, KnotVector, Length,
- MergedKVt, LengthKVt - Order);
-
- RefinedCrv = BspCrvNew(Crv -> Length + n, Order, Crv -> PType);
-
- /* Update the knot vector. */
- IritFree((VoidPtr) RefinedCrv -> KnotVector);
- RefinedCrv -> KnotVector = MergedKVt;
-
- /* Update the control mesh */
- for (j = IsNotRational; j <= MaxCoord; j++) {
- CagdRType
- *ROnePts = RefinedCrv -> Points[j],
- *OnePts = Crv -> Points[j];
- for (i = 0; i < RefinedCrv -> Length; i++, ROnePts++)
- CAGD_ALPHA_BLEND( A, i, OnePts, ROnePts );
- }
- BspKnotFreeAlphaCoef(A);
- }
-
- BspKnotMakeRobustKV(RefinedCrv -> KnotVector,
- RefinedCrv -> Order + RefinedCrv -> Length);
-
- return RefinedCrv;
- }
-
- /******************************************************************************
- * Returns a new curve, identical to the original but with order N. *
- * Degree raise by multiplying by a constant 1 curve of order *
- * (NewOrder - Order). *
- ******************************************************************************/
- CagdCrvStruct *BspCrvDegreeRaiseN(CagdCrvStruct *Crv, int NewOrder)
- {
- int i, j, RaisedOrder,
- Order = Crv -> Order,
- Length = Crv -> Length,
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType),
- KvLen1 = Order + Length - 1;
- CagdCrvStruct *RaisedCrv, *UnitCrv;
- CagdRType
- *Kv = Crv -> KnotVector;
-
- if (NewOrder < Order) {
- FATAL_ERROR(CAGD_ERR_WRONG_ORDER);
- return NULL;
- }
- RaisedOrder = NewOrder - Order + 1;
-
- UnitCrv = BspCrvNew(RaisedOrder, RaisedOrder,
- CAGD_MAKE_PT_TYPE(FALSE, MaxCoord));
- for (i = 0; i < RaisedOrder * 2; i++)
- UnitCrv -> KnotVector[i] = i >= RaisedOrder ? Kv[KvLen1] : Kv[0];
- for (i = 1; i <= MaxCoord; i++)
- for (j = 0; j < RaisedOrder; j++)
- UnitCrv -> Points[i][j] = 1.0;
-
- RaisedCrv = BspCrvMult(Crv, UnitCrv);
-
- CagdCrvFree(UnitCrv);
-
- return RaisedCrv;
- }
-
- /******************************************************************************
- * Return a new curve, identical to the original but with one degree higher *
- ******************************************************************************/
- CagdCrvStruct *BspCrvDegreeRaise(CagdCrvStruct *Crv)
- {
- CagdBType
- IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
- int i, i2, j, RaisedLen,
- Order = Crv -> Order,
- Length = Crv -> Length,
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
- CagdCrvStruct *RaisedCrv;
-
- if (Order > 2)
- return BspCrvDegreeRaiseN(Crv, Order + 1);
-
- /* If curve is linear, degree raising means basically to increase the */
- /* knot multiplicity of each segment by one and add a middle point for */
- /* each such segment. */
- RaisedLen = Length * 2 - 1;
- RaisedCrv = BspCrvNew(RaisedLen, Order + 1, Crv -> PType);
-
- /* Update the control polygon; */
- for (j = IsNotRational; j <= MaxCoord; j++) /* First point. */
- RaisedCrv -> Points[j][0] = Crv -> Points[j][0];
-
- for (i = 1, i2 = 1; i < Length; i++, i2 += 2)
- for (j = IsNotRational; j <= MaxCoord; j++) {
- RaisedCrv -> Points[j][i2] =
- Crv -> Points[j][i-1] * 0.5 + Crv -> Points[j][i] * 0.5;
- RaisedCrv -> Points[j][i2 + 1] = Crv -> Points[j][i];
- }
-
- /* Update the knot vector. */
- for (i = 0; i < 3; i++)
- RaisedCrv -> KnotVector[i] = Crv -> KnotVector[0];
-
- for (i = 2, j = 3; i < Length; i++, j += 2)
- RaisedCrv -> KnotVector[j] = RaisedCrv -> KnotVector[j + 1] =
- Crv -> KnotVector[i];
-
- for (i = j; i < j + 3; i++)
- RaisedCrv -> KnotVector[i] = Crv -> KnotVector[Length];
-
- return RaisedCrv;
- }
-
- /******************************************************************************
- * Return a normalized vector, equal to the tangent to Crv at parameter t. *
- * Algorithm: insert (order - 1) knots and return control polygon tangent. *
- ******************************************************************************/
- CagdVecStruct *BspCrvTangent(CagdCrvStruct *Crv, CagdRType t)
- {
- static CagdVecStruct P2;
- CagdVecStruct P1, *T;
- CagdRType TMin, TMax;
- int k = Crv -> Order,
- Len = Crv -> Length,
- Index = BspKnotLastIndexL(Crv -> KnotVector, k + Len, t);
- CagdPointType
- PType = Crv -> PType;
- CagdCrvStruct *RefinedCrv;
-
- if (!BspKnotParamInDomain(Crv -> KnotVector, Len, k, t))
- FATAL_ERROR(CAGD_ERR_T_NOT_IN_CRV);
-
- BspCrvDomain(Crv, &TMin, &TMax);
-
- if (APX_EQ(t, TMin)) {
- /* Use Crv starting tangent direction. */
- CagdCoerceToE3(P1.Vec, Crv -> Points, 0, PType);
- CagdCoerceToE3(P2.Vec, Crv -> Points, 1, PType);
- }
- else if (APX_EQ(t, TMax)) {
- /* Use Crv ending tangent direction. */
- CagdCoerceToE3(P1.Vec, Crv -> Points, Len - 2, PType);
- CagdCoerceToE3(P2.Vec, Crv -> Points, Len - 1, PType);
- }
- else {
- RefinedCrv = BspCrvKnotInsertNSame(Crv, t, k - 1);
-
- CagdCoerceToE3(P1.Vec, RefinedCrv -> Points, Index, PType);
- CagdCoerceToE3(P2.Vec, RefinedCrv -> Points, Index + 1, PType);
-
- CagdCrvFree(RefinedCrv);
- }
-
- CAGD_SUB_VECTOR(P2, P1);
-
- if (CAGD_LEN_VECTOR(P2) < SQR(EPSILON)) {
- if (AttrGetIntAttrib(Crv -> Attr, "_tan") != TRUE) {
- /* Try to move a little. This location has zero speed. However, */
- /* do it only once since we can be here forever. The "_tan" */
- /* attribute guarantee we will try to move EPSILON only once. */
- AttrSetIntAttrib(&Crv -> Attr, "_tan", TRUE);
-
- T = BspCrvTangent(Crv, t - TMin < TMax - t ? t + EPSILON
- : t - EPSILON);
-
- AttrFreeOneAttribute(&Crv -> Attr, "_tan");
-
- return T;
- }
- else {
- /* A zero length vector signals failure to compute tangent. */
- return &P2;
- }
- }
- else {
- CAGD_NORMALIZE_VECTOR(P2); /* Normalize the vector. */
-
- return &P2;
- }
- }
-
- /******************************************************************************
- * Return a normalized vector, equal to the binormal to Crv at parameter t. *
- * Algorithm: insert (order - 1) knots and using 3 consecutive control points *
- * at the refined location (p1, p2, p3), compute to binormal to be the cross *
- * product of the two vectors (p1 - p2) and (p2 - p3). *
- ******************************************************************************/
- CagdVecStruct *BspCrvBiNormal(CagdCrvStruct *Crv, CagdRType t)
- {
- static CagdVecStruct P3;
- CagdVecStruct P1, P2;
- CagdRType TMin, TMax;
- int k = Crv -> Order,
- Len = Crv -> Length,
- Index = BspKnotLastIndexL(Crv -> KnotVector, k + Len, t);
- CagdPointType
- PType = Crv -> PType;
- CagdCrvStruct *RefinedCrv;
-
- if (!BspKnotParamInDomain(Crv -> KnotVector, Len, k, t))
- FATAL_ERROR(CAGD_ERR_T_NOT_IN_CRV);
-
- /* Can not compute for linear curves. */
- if (k <= 2)
- return NULL;
-
- /* For planar curves, B is trivially the Z axis. */
- if (CAGD_NUM_OF_PT_COORD(Crv -> PType) == 2) {
- P3.Vec[0] = P3.Vec[1] = 0.0;
- P3.Vec[2] = 1.0;
- return &P3;
- }
-
- BspCrvDomain(Crv, &TMin, &TMax);
-
- if (APX_EQ(t, TMin)) {
- /* Use Crv starting tangent direction. */
- CagdCoerceToE3(P1.Vec, Crv -> Points, 0, PType);
- CagdCoerceToE3(P2.Vec, Crv -> Points, 1, PType);
- CagdCoerceToE3(P3.Vec, Crv -> Points, 2, PType);
- }
- else if (APX_EQ(t, TMax)) {
- /* Use Crv ending tangent direction. */
- CagdCoerceToE3(P1.Vec, Crv -> Points, Len - 3, PType);
- CagdCoerceToE3(P2.Vec, Crv -> Points, Len - 2, PType);
- CagdCoerceToE3(P3.Vec, Crv -> Points, Len - 1, PType);
- }
- else {
- RefinedCrv = BspCrvKnotInsertNSame(Crv, t, k - 1);
-
- CagdCoerceToE3(P1.Vec, RefinedCrv -> Points, Index, PType);
- CagdCoerceToE3(P2.Vec, RefinedCrv -> Points, Index + 1, PType);
- CagdCoerceToE3(P3.Vec, RefinedCrv -> Points, Index + 2, PType);
-
- CagdCrvFree(RefinedCrv);
- }
-
- CAGD_SUB_VECTOR(P1, P2);
- CAGD_SUB_VECTOR(P2, P3);
-
- CROSS_PROD(P3.Vec, P1.Vec, P2.Vec);
-
- if ((t = CAGD_LEN_VECTOR(P3)) < EPSILON)
- return NULL;
- else
- CAGD_DIV_VECTOR(P3, t); /* Normalize the vector. */
-
- return &P3;
- }
-
- /******************************************************************************
- * Return a normalized vector, equal to the normal to Crv at parameter t. *
- * Algorithm: returns the cross product of the curve tangent and binormal. *
- ******************************************************************************/
- CagdVecStruct *BspCrvNormal(CagdCrvStruct *Crv, CagdRType t)
- {
- static CagdVecStruct N, *T, *B;
-
- T = BspCrvTangent(Crv, t);
- B = BspCrvBiNormal(Crv, t);
-
- if (T == NULL || B == NULL)
- return NULL;
-
- CROSS_PROD(N.Vec, T -> Vec, B -> Vec);
-
- CAGD_NORMALIZE_VECTOR(N); /* Normalize the vector. */
-
- return &N;
- }
-
- /******************************************************************************
- * Return a new curve, equal to the derived curve. *
- * Let old control polygon be P(i), i = 0 to k-1, and Q(i) be new one then: *
- * Q(i) = (k - 1) * (P(i+1) - P(i)) / (Kv(i + k) - Kv(i + 1)), i = 0 to k-2. *
- ******************************************************************************/
- CagdCrvStruct *BspCrvDerive(CagdCrvStruct *Crv)
- {
- CagdBType
- IsNotRational = !CAGD_IS_RATIONAL_CRV(Crv);
- int i, j,
- k = Crv -> Order,
- Len = Crv -> Length,
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
- CagdRType
- *Kv = Crv -> KnotVector;
- CagdCrvStruct *DerivedCrv;
-
- if (!IsNotRational)
- return BspCrvDeriveRational(Crv);
- else if (k < 2)
- FATAL_ERROR(CAGD_ERR_LIN_NO_SUPPORT);
-
- DerivedCrv = BspCrvNew(Len - 1, k - 1, Crv -> PType);
-
- for (i = 0; i < Len - 1; i++) {
- CagdRType
- Denom = Kv[i + k] - Kv[i + 1];
-
- for (j = IsNotRational; j <= MaxCoord; j++)
- DerivedCrv -> Points[j][i] = (k - 1) *
- (Crv -> Points[j][i + 1] - Crv -> Points[j][i]) / Denom;
- }
-
- CAGD_GEN_COPY(DerivedCrv -> KnotVector,
- &Crv -> KnotVector[1],
- sizeof(CagdRType) * (k + Len - 2));
-
- return DerivedCrv;
- }
-
- /******************************************************************************
- * Return a new Bspline curve, equal to the integral of the given Bspline crv. *
- * The given Bspline curve should be nonrational. *
- * *
- * l l l l+1 *
- * / /- - / - P - *
- * | | \ n \ | n \ i \ n+1 *
- * | C(t) = | / P B (t) = / P | B (t) = / ----- / ( t - t ) B (t) = *
- * / / - i i - i / i - n + 1 - j+n j j *
- * i=0 i=0 i=0 j=i+1 *
- * *
- * l+1 j-1 *
- * - - *
- * 1 \ \ n+1 *
- * = ----- / / P ( t - t ) B (t) *
- * n + 1 - - i j+n j j *
- * j=1 i=0 *
- * *
- ******************************************************************************/
- CagdCrvStruct *BspCrvIntegrate(CagdCrvStruct *Crv)
- {
- int i, j, k,
- n = Crv -> Order,
- Len = Crv -> Length,
- MaxCoord = CAGD_NUM_OF_PT_COORD(Crv -> PType);
- CagdCrvStruct *IntCrv;
- CagdRType
- *Kv = Crv -> KnotVector;
-
- if (CAGD_IS_RATIONAL_CRV(Crv))
- FATAL_ERROR(CAGD_ERR_RATIONAL_NO_SUPPORT);
-
- IntCrv = BspCrvNew(Len + 1, n + 1, Crv -> PType);
-
- /* Copy the knot vector and duplicate the two end knots. */
- CAGD_GEN_COPY(&IntCrv -> KnotVector[1], Kv, sizeof(CagdRType) * (Len + n));
- IntCrv -> KnotVector[0] = Kv[0];
- IntCrv -> KnotVector[Len + n + 1] = Kv[Len + n - 1];
- Kv = IntCrv -> KnotVector;
-
- for (k = 1; k <= MaxCoord; k++) {
- CagdRType
- *Points = Crv -> Points[k],
- *IntPoints = IntCrv -> Points[k];
-
- for (j = 0; j < Len + 1; j++) {
- IntPoints[j] = 0.0;
- for (i = 0; i < j; i++)
- IntPoints[j] += Points[i] * (Kv[i + n + 1] - Kv[i + 1]);
- IntPoints[j] /= n;
- }
- }
-
- return IntCrv;
- }
-
- /******************************************************************************
- * Return a new linear Bspline curve constructed from the given polyline. *
- ******************************************************************************/
- CagdCrvStruct *CnvrtPolyline2LinBsplineCrv(CagdPolylineStruct *Poly)
- {
- int i,
- Length = Poly -> Length;
- CagdCrvStruct
- *Crv = BspCrvNew(Length, 2, CAGD_PT_E3_TYPE);
- CagdRType
- **Points = Crv -> Points;
- CagdPtStruct
- *Pts = Poly -> Polyline;
-
- BspKnotUniformOpen(Length, 2, Crv -> KnotVector);
-
- for (i = 0; i < Length; i++, Pts++) {
- Points[1][i] = Pts -> Pt[0];
- Points[2][i] = Pts -> Pt[1];
- Points[3][i] = Pts -> Pt[2];
- }
-
- return Crv;
- }
-